package com.caijb.juc;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author caijb
 * @version 1.0
 * @data 2025/10/27 21:54
 */
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
//        countDownLatchDemo();
        raceStartDemo();
    }

    private static void countDownLatchDemo() throws InterruptedException {
        // 创建一个计数器，初始值为5
        CountDownLatch countDownLatch = new CountDownLatch(5);
        // 创建5个线程
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "线程开始执行");
                // 线程执行完毕，计数器减1
                countDownLatch.countDown();
            }, "线程" + i).start();
        }
        countDownLatch.await();
        System.out.println("所有线程执行完毕");
    }

    /**
     * 场景2: 多个运动员准备就绪后开始比赛
     */
    public static void raceStartDemo() throws InterruptedException {
        System.out.println("=== 场景2: 运动员比赛开始 ===");

        int playerCount = 5;
        CountDownLatch readyLatch = new CountDownLatch(playerCount);  // 运动员准备就绪
        CountDownLatch startLatch = new CountDownLatch(1);            // 发令枪信号
        CountDownLatch finishLatch = new CountDownLatch(playerCount); // 比赛完成

        ExecutorService executor = Executors.newFixedThreadPool(playerCount);

        // 创建运动员
        for (int i = 1; i <= playerCount; i++) {
            final int playerId = i;
            executor.submit(() -> {
                try {
                    // 运动员准备
                    System.out.println("运动员" + playerId + "正在准备...");
                    Thread.sleep((long) (Math.random() * 2000) + 1000);  // 随机准备时间
                    System.out.println("运动员" + playerId + "准备就绪");

                    // 准备完成后，通知裁判
                    readyLatch.countDown();

                    // 等待发令枪信号
                    startLatch.await();
                    System.out.println("运动员" + playerId + "开始跑步");

                    // 模拟跑步时间
                    Thread.sleep((long) (Math.random() * 5000) + 3000);
                    System.out.println("运动员" + playerId + "到达终点");

                    // 完成比赛
                    finishLatch.countDown();

                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.out.println("运动员" + playerId + "被中断");
                }
            });
        }

        // 裁判线程
        Thread caipan = new Thread(() -> {
            try {
                System.out.println("裁判: 等待所有运动员准备就绪...");
                readyLatch.await();  // 等待所有运动员准备就绪
                System.out.println("裁判: 所有运动员准备就绪，准备发令");

                Thread.sleep(1000);
                System.out.println("裁判: 各就各位");
                Thread.sleep(1000);
                System.out.println("裁判: 预备");
                Thread.sleep(1000);
                System.out.println("裁判: 跑！");

                // 发令枪信号
                startLatch.countDown();

                System.out.println("裁判: 等待比赛结果...");
                finishLatch.await();  // 等待所有运动员完成比赛
                System.out.println("裁判: 比赛结束，所有运动员完成比赛");

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("裁判被中断");
            }
        });

        caipan.start();

        // 等待裁判线程完成
        caipan.join();
        executor.shutdown();
        System.out.println();
    }
}
